package com.lagou.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;


@Component
@Slf4j
public class IpFlushFirewall {


    @Autowired
    private StringRedisTemplate redisTemplate;


    /**
     * 最大ip限制次数maxRequestCount
     */
    @Value("${config.request.iplimit.maxRequestCount}")
    private int maxLimitIpHit;
    /**
     * 检查时效,单位:分钟
     */
    @Value("${config.request.iplimit.intervalMinutes}")
    private int checkLimitIpHitInterval;



    public static String getRequestClientIP(ServerHttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        String ip = headers.getFirst("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            if (ip.indexOf(",") != -1) {
                ip = ip.split(",")[0];
            }
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("X-Real-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddress().getAddress().getHostAddress();
        }

        return ip;
    }



    public boolean isIpLimited(String reqIp) {
        String ipHitCache = getIpHitCacheKey(reqIp);
        // 先取旧数据作为本次判断，再记录本次访问
        String hitsStr = redisTemplate.opsForValue().get(ipHitCache);

        log.info("  ipHitCache:{}   已经访问了hitsStr:{}",ipHitCache,hitsStr);
        // 新周期内，首次访问
        if (hitsStr == null) {
            recordNewIpRequest(reqIp);
            return false;
        }
        // 之前有命中
        // 总数未超限，直接通过
        if (!isOverMaxLimit(Integer.valueOf(hitsStr) + 1)) {
            redisTemplate.opsForValue().increment(getIpHitCacheKey(reqIp));
            return false;
        }
        return true;
    }

    // 是否超过最大限制
    public boolean isOverMaxLimit(Integer nowCount) {
        return nowCount > maxLimitIpHit;
    }

    // 每次访问必须记录
    public void recordNewIpRequest(String reqIp) {
        // 自增访问量
        redisTemplate.opsForValue().set(getIpHitCacheKey(reqIp), "1",checkLimitIpHitInterval, TimeUnit.MINUTES);
    }


    // ip 访问计数器缓存key
    public String getIpHitCacheKey(String reqIp) {
        return "secure.ip.limit." + reqIp;
    }


}
